<template>
  <n-tooltip :show="showPopover" placement="top">
    <template #trigger>
      <div class="wrapper" v-bind="$attrs">
        <div ref="fakeTextRef" class="fake_text">{{ text }}</div>
        <div
          ref="tagsRef"
          @mouseenter="() => (!showMore && showExpand ? (showPopover = true) : '')"
          @mouseleave="() => (showPopover = false)"
          class="tags_wrapper"
          :class="[showExpand ? 'line-clamp' : undefined]"
        >
          <span v-if="showExpand" class="expand" @click="changeState">
            {{ !showMore ? expandText : packText }}
          </span>
          {{ text }}
        </div>
      </div>
    </template>

    <!-- 暴露提示框给使用者自定义 -->
    <slot name="diyTooltip">
      {{ text }}
    </slot>
  </n-tooltip>
</template>

<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    text: string // 展示文本
    diyTooltip?: boolean // 是否自定义toolTip
    propLineClamp?: number // 最大行数省略
    expandText?: string // 展开文本
    packText?: string // 收起文本
  }>(),
  {
    diyTooltip: false,
    propLineClamp: 2,
    expandText: '展开',
    packText: '收起'
  }
)

const tagsRef = ref<HTMLElement | null>(null)
// 伪造文本盒子，固定一行展示，
// 用于获取一行文本展示高度，
// 以此判断是否需要展示收起展开按钮
const fakeTextRef = ref<HTMLElement | null>(null)
const lineClamp = ref<number>() // 最大行数省略
const showMore = ref(false) // 控制按钮文字为展开还是收起
const showPopover = ref(false) // 控制toolTip的展示
const showExpand = ref(false) // 控制展开收起按钮

function changeState() {
  showMore.value = !showMore.value
  if (showMore.value) {
    lineClamp.value = undefined
  } else {
    lineClamp.value = props.propLineClamp
  }
}

// 计算是否显示，展开收起按钮
function calculateShowExpand() {
  const oneLineHeight = (fakeTextRef.value as HTMLElement).clientHeight // 获取一行展示高度
  const height = (tagsRef.value as HTMLElement).clientHeight // 获取当前文本换行后总高度
  if (height > oneLineHeight * props.propLineClamp) {
    showExpand.value = true
  }
}

onMounted(calculateShowExpand)

watch(
  () => props.propLineClamp,
  (val) => {
    if (val) {
      lineClamp.value = val
    }
  },
  { immediate: true }
)
</script>

<style lang="less" scoped>
.wrapper {
  position: relative;
  display: flex;
  // padding-right: 34px;

  .fake_text {
    position: absolute;
    white-space: nowrap;
    opacity: 0;
  }
  .tags_wrapper {
    position: relative;
    display: -webkit-box;
    flex-grow: 1;
    word-break: break-all;
    text-overflow: ellipsis;
    overflow: hidden;
    -webkit-box-orient: vertical;

    width: 100%;
    margin-bottom: -4px;
    transition: all 0.5s linear;

    &.line-clamp {
      -webkit-line-clamp: v-bind(lineClamp);
    }
    &::before {
      content: '';
      float: right;
      width: 0;
      height: calc(100% - 18px);
      background: red;
    }
  }

  .expand {
    font-size: 14px;
    line-height: 14px;
    float: right;
    clear: both;
    color: #1d85ff;
    cursor: pointer;
  }
}
</style>
